using System.Collections.Generic;
using FixMath;
using UniFramework.Actor;
using UniFramework.Battle;
using UnityEngine;

namespace UniFramework.Aoe
{
	/// <summary>
	/// Aoe生命周期管理
	/// </summary>
	public class AoeSystem : MonoBehaviour
	{
		private List<LogicAoe> _aoeList = new List<LogicAoe>();

		public void OnLogicFrameUpdate()
		{
			if (_aoeList.Count <= 0) return;
			LogicActor[] actors = GameObject.FindObjectsByType<LogicActor>(FindObjectsSortMode.None);
			LogicBullet[] bullets = GameObject.FindObjectsByType<LogicBullet>(FindObjectsSortMode.None);
			FixInt timePassed = LogicFrameConfig.logicFrameIntervalFixInt;
			List<LogicAoe> needRemove = new List<LogicAoe>();
			foreach (var aoe in _aoeList)
			{
				if (!aoe) continue;
				if (aoe.justCreated)
				{
					aoe.justCreated = false;
					//遍历角色
					foreach (var actor in actors)
					{
						if (FixIntVector3.Distance(actor.LogicPos, aoe.LogicPos) <= aoe.aoeObj.radius)
						{
							aoe.characterInRangeList.Add(actor);
						}
					}

					//遍历子弹
					foreach (var bullet in bullets)
					{
						if (FixIntVector3.Distance(bullet.LogicPos, aoe.LogicPos) <= aoe.aoeObj.radius)
						{
							aoe.bulletInRangeList.Add(bullet);
						}
					}

					//生命周期创建
					aoe.aoeObj.aoeConfig.onCreate?.Invoke(aoe);
					if (aoe.characterInRangeList.Count > 0)
						aoe.aoeObj.aoeConfig.onChaEnter?.Invoke(aoe, aoe.characterInRangeList);
					if (aoe.bulletInRangeList.Count > 0)
						aoe.aoeObj.aoeConfig.onBulletEnter?.Invoke(aoe, aoe.bulletInRangeList);
				}
				else
				{
					//看哪些角色进入了aoe
					List<LogicActor> enterActor = new List<LogicActor>();
					foreach (var actor in actors)
					{
						if (aoe.characterInRangeList.Contains(actor)) continue;
						if (FixIntVector3.Distance(actor.LogicPos, aoe.LogicPos) <= aoe.aoeObj.radius)
						{
							enterActor.Add(actor);
						}
					}

					foreach (var actor in enterActor)
					{
						if (actor != null && !actor.actorState.property.dead)
						{
							aoe.characterInRangeList.Add(actor);
						}
					}

					if (enterActor.Count > 0) aoe.aoeObj.aoeConfig.onChaEnter?.Invoke(aoe, enterActor);


					//已经存在的aoe去看看哪些人在当前帧离开了
					List<LogicActor> leaveActor = new List<LogicActor>();
					List<LogicActor> toRemoveActor = new List<LogicActor>();
					foreach (var actor in aoe.characterInRangeList)
					{
						if (actor != null)
						{
							if (FixIntVector3.Distance(aoe.LogicPos, actor.LogicPos) > aoe.aoeObj.radius)
							{
								leaveActor.Add(actor);
								toRemoveActor.Add(actor);
							}
						}
						else
						{
							toRemoveActor.Add(actor);
						}
					}

					foreach (var actor in toRemoveActor) aoe.characterInRangeList.Remove(actor);
					if (leaveActor.Count > 0) aoe.aoeObj.aoeConfig.onChaLeave?.Invoke(aoe, leaveActor);


					//看哪些子弹离开了
					List<LogicBullet> leaveBullet = new List<LogicBullet>();
					List<LogicBullet> toRemoveBullet = new List<LogicBullet>();
					foreach (var bullet in bullets)
					{
						if (bullet != null)
						{
							if (FixIntVector3.Distance(bullet.LogicPos, aoe.LogicPos) > aoe.aoeObj.radius)
							{
								leaveBullet.Add(bullet);
								toRemoveBullet.Add(bullet);
							}
						}
						else
						{
							toRemoveBullet.Add(bullet);
						}
					}

					foreach (var bullet in toRemoveBullet) aoe.bulletInRangeList.Remove(bullet);
					if (leaveBullet.Count > 0) aoe.aoeObj.aoeConfig.onBulletLeave?.Invoke(aoe, leaveBullet);

					toRemoveActor.Clear();
					toRemoveBullet.Clear();

					List<LogicBullet> enterBullet = new List<LogicBullet>();
					foreach (var bullet in bullets)
					{
						if (aoe.bulletInRangeList.Contains(bullet)) continue;
						if (FixIntVector3.Distance(bullet.LogicPos, aoe.LogicPos) <= aoe.aoeObj.radius)
						{
							enterBullet.Add(bullet);
						}
					}

					foreach (var bullet in enterBullet)
					{
						if (bullet != null)
						{
							aoe.bulletInRangeList.Add(bullet);
						}
					}

					if (enterBullet.Count > 0) aoe.aoeObj.aoeConfig.onBulletEnter?.Invoke(aoe, enterBullet);
				}

				aoe.aoeObj.duration -= timePassed;
				aoe.aoeObj.timePassed += timePassed;
				if (aoe.aoeObj.duration <= 0)
				{
					aoe.aoeObj.aoeConfig.onRemoved?.Invoke(aoe);
					needRemove.Add(aoe);
					aoe.OnDie();
				}
				else
				{
					FixInt duration = aoe.aoeObj.duration;
					FixInt tickTime = aoe.aoeObj.aoeConfig.tickTime;
					if (tickTime > 0 && duration % tickTime == 0)
					{
						aoe.aoeObj.aoeConfig.onTick?.Invoke(aoe);
					}
				}
			}

			foreach (var aoe in needRemove)
			{
				_aoeList.Remove(aoe);
			}
		}

		public void CreateAoe(AoeObj aoeObj)
		{
			GameObject aoeGameObj = new GameObject($"Aoe_{aoeObj.aoeConfig.id}");
			var logicAoe = aoeGameObj.AddComponent<LogicAoe>();
			logicAoe.aoeObj = aoeObj;
			aoeGameObj.transform.position = aoeObj.position.ToVector3();
			logicAoe.OnCreate();
			_aoeList.Add(logicAoe);
		}
	}
}